/*
 * BSW_Boot.c
 *
 *  Created on: Oct 16, 2025
 *      Author: ADMIN
 */


#include "BSW_Boot.h"

/* BootLoad Gloabal Parameter */
uint8 BSW_Boot_u8NowStatus = 0;
uint8 BSW_Boot_u8LastStatus = 0;
uint16 BSW_Boot_u16TotalPocketNum =0;
/* BootLoad Internal Parameter */
static boolean bFisrtIntoFlag_StandBy = 0;
static boolean bFisrtIntoFlag_StayBoot = 0;
static boolean bFisrtIntoFlag_DateDeal = 0;
static boolean bFisrtIntoFlag_FlashDeal = 0;
static boolean bFisrtIntoFlag_Fault = 0;
static boolean bFisrtIntoFlag_JunpApp = 0;

/* Define about NVIC enable and disable */
#define ENABLE_INT() __set_PRIMASK(0)  /* enable  NVIC*/
#define DISABLE_INT() __set_PRIMASK(1) /* disable NVIC */
void (*SysMemBootJump)(void);        
static uint32_t AppAddr = MCU_FLASH_APP_StartAddress;    /* APPDress */


/* BootLoad Init Function */
void BSW_Boot_Init(void)
{
    Boot_Status_Timer.Start(&Boot_Status_Timer);
    BSW_Boot_u8NowStatus = BOOT_STANDBY_STA;
    BSW_Boot_u8LastStatus = BOOT_INIT_STA;
}


/* BootLoad Main Function */
void BSW_Boot_main(void)
{
    switch (BSW_Boot_u8NowStatus)
    {
        case BOOT_STANDBY_STA:
            /* BOOT_STANDBY_STA code */
            if (BSW_Boot_u8LastStatus != BOOT_STANDBY_STA)
            {
                /* >>>>Entry Action */
                Entry_StandBy_Func();

                if (bFisrtIntoFlag_StandBy == 0)
                {
                    /* >>>>First Entry Action */
                    FirstEntry_StandBy_Func();
                    bFisrtIntoFlag_StandBy = 1;
                }
                BSW_Boot_u8LastStatus = BOOT_STANDBY_STA;
            }
            
            break;

        case BOOT_STAYBOOT_STA:
            /* BOOT_STAYBOOT_STA code */
            if (BSW_Boot_u8LastStatus != BOOT_STAYBOOT_STA)
            {
                /* >>>>Entry Action */
                Entry_StayBoot_Func();
                
                if (bFisrtIntoFlag_StayBoot == 0)
                {
                    /* >>>>First Entry Action */
                    FirstEntry_StayBoot_Func();
                    bFisrtIntoFlag_StayBoot = 1;
                }
                BSW_Boot_u8LastStatus = BOOT_STAYBOOT_STA;
            }
            break;

        case BOOT_DATEDEAL_STA:
            /* BOOT_DATEDEAL_STA code */
            if (BSW_Boot_u8LastStatus != BOOT_DATEDEAL_STA)
            {
                /* >>>>Entry Action */
                Entry_DateDeal_Func();

                if (bFisrtIntoFlag_DateDeal == 0)
                {
                    /* >>>>First Entry Action */
                    FirstEntry_DateDeal_Func();
                    bFisrtIntoFlag_DateDeal = 1;
                }
                BSW_Boot_u8LastStatus = BOOT_DATEDEAL_STA;
            }
            break;

        case BOOT_FAULT_STA:
            /* BOOT_FAULT_STA code */
            if (BSW_Boot_u8LastStatus != BOOT_FAULT_STA)
            {
                /* >>>>Entry Action */
                Entry_Fault_Func();
                
                if (bFisrtIntoFlag_Fault == 0)
                {
                    /* >>>>First Entry Action */
                    FirstEntry_Fault_Func();
                    bFisrtIntoFlag_Fault = 1;
                }
                BSW_Boot_u8LastStatus = BOOT_FAULT_STA;
            }            
            break; 

        case BOOT_FLASHDEAL_STA:
            /* BOOT_FLASHDEAL_STA code */
            if (BSW_Boot_u8LastStatus != BOOT_FLASHDEAL_STA)
            {
                /* >>>>Entry Action */
                Entry_FlashDeal_Func();
                
                if (bFisrtIntoFlag_FlashDeal == 0)
                {
                    /* >>>>First Entry Action */
                    FirstEntry_FlashDeal_Func();
                    bFisrtIntoFlag_FlashDeal = 1;
                }
                BSW_Boot_u8LastStatus = BOOT_FLASHDEAL_STA;
            }               
            break;

        case BOOT_JUMPAPP_STA:
            /* BOOT_JUMPAPP_STA code */
            if (BSW_Boot_u8LastStatus != BOOT_JUMPAPP_STA)
            {
                /* >>>>Entry Action */
                Entry_JumpApp_Func();
                
                if (bFisrtIntoFlag_JunpApp == 0)
                {
                    /* >>>>First Entry Action */
                    FirstEntry_JumpApp_Func();
                    bFisrtIntoFlag_JunpApp = 1;
                }
                BSW_Boot_u8LastStatus = BOOT_JUMPAPP_STA;
            }
            break; 

        default:
            break;
    }
}

void Entry_StandBy_Func(void)
{
    my_printf("Get into BOOT_STANDBY_STA\r\n");
    Cycle_500ms_Timer.Start(&Cycle_500ms_Timer);
}

void Entry_StayBoot_Func(void)
{
    my_printf("Get into BOOT_STAYBOOT_STA\r\n");
    Boot_Status_Timer.Stop(&Boot_Status_Timer);
}

void Entry_DateDeal_Func(void)
{
    my_printf("Get into BOOT_DATEDEAL_STA\r\n");
    Boot_Status_Timer.Stop(&Boot_Status_Timer);
    /* Date Deal Action */
    /* Step1 : Copy receive data from uart to SPI Flash */
    uint32_t deal_address = RS485_UART_Type.ReceiveDateIndex[RS485_UART_Type.ReceiveByteLen-3]*256;
    BSP_W25Qx_Write(RS485_UART_Type.ReceiveDateIndex, deal_address, RS485_UART_Type.ReceiveByteLen-3);
    /* Step2 : Read and printf Flash Date */
    uint8 Read_Flash_Arr[256] ;
    BSP_W25Qx_Read(Read_Flash_Arr,deal_address, RS485_UART_Type.ReceiveByteLen-3);
    RS485_ComtralIO.Set_High(&RS485_ComtralIO);
    RS485_UART_Type.SendByteLen = RS485_UART_Type.ReceiveByteLen-3;
    RS485_UART_Type.SendDateIndex = Read_Flash_Arr;
    RS485_UART_Type.Send_Date(&RS485_UART_Type);
    RS485_ComtralIO.Set_Low(&RS485_ComtralIO);
    /* Step3 : Get into StandBy */
    BSW_Boot_u16TotalPocketNum ++;
    BSW_Boot_u8NowStatus = BOOT_STAYBOOT_STA;
}

void Entry_Fault_Func(void)
{
    my_printf("Get into BOOT_FAULT_STA\r\n");
    Boot_Status_Timer.Stop(&Boot_Status_Timer);
}

void Entry_FlashDeal_Func(void)
{
    my_printf("Get into BOOT_FLASHDEAL_STA\r\n");
    Boot_Status_Timer.Stop(&Boot_Status_Timer);
    /* Step1 : Copy SPI Flash Date to MCU Flash */
	HAL_FLASH_Unlock();
	uint32_t sectorError = 0;
	FLASH_EraseInitTypeDef EraseInitStruct;
	EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;   // 按扇区擦除
	EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;  // 电压范围，适用于 2.7V - 3.6V
	EraseInitStruct.Sector = FLASH_SECTOR_2;               // 要擦除的扇区号
	EraseInitStruct.NbSectors = 7;                         // 要擦除的扇区数量
	if (HAL_FLASHEx_Erase(&EraseInitStruct, &sectorError) != HAL_OK) {
	  // 擦除出错，sectorError 包含了出错的扇区号
	  my_printf(">>>>>Erase MCU Flash ERR!!!\r\n");
	  Error_Handler();
	}
	my_printf(">>>>>Erase MCU Flash Done\r\n");
	uint32_t app_startaddress = MCU_FLASH_APP_StartAddress;
	for (uint32_t i=0;i<BSW_Boot_u16TotalPocketNum;i++)
	{
		uint8_t read_arr_256byte[256];
		BSP_W25Qx_Read(read_arr_256byte,i*256,256);
		uint32_t flash_write_arr_64word[64];
		memcpy(flash_write_arr_64word, read_arr_256byte, 256);
		for (int i = 0; i < 64; i++)
		{
		    HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, app_startaddress, flash_write_arr_64word[i]);
		    app_startaddress += 4;
		}
		my_printf(">>>>>Write MCU Flash pocket %d\r\n",i);
	}
	HAL_FLASH_Lock();    
    /* Step2 : Read MCU Flash Date */

    /* Step3 : Get into JumpApp */
    BSW_Boot_u8NowStatus = BOOT_JUMPAPP_STA;
}

void Entry_JumpApp_Func(void)
{
    my_printf("Get into BOOT_JUMPAPP_STA\r\n");
    Blue_LED_Type.Set_High(&Blue_LED_Type);
    /* Check target Flash sector is NULL or not */
    uint32_t app_startaddress = MCU_FLASH_APP_StartAddress;
    uint8_t MCU_APP_Flash_NoneFlag;
    if (*(volatile uint8_t*)app_startaddress == 0xFF && *(volatile uint8_t*)(app_startaddress+1) == 0xFF && *(volatile uint8_t*)(app_startaddress+254) == 0xFF && *(volatile uint8_t*)(app_startaddress+255) == 0xFF)
    {
    	MCU_APP_Flash_NoneFlag=1;
    }
    else
    {
    	MCU_APP_Flash_NoneFlag=0;
    }
    
	if (MCU_APP_Flash_NoneFlag == 0)
	{
		JumpToApp();
		my_printf(">>>>>JumpAPP ERR!!!\r\n");
	}
	else
	{
		my_printf(">>>>>JumpAPP ERR because MCU_APP_Flash_None!!!\r\n");
	}    
}

void FirstEntry_StandBy_Func(void)
{
    /* Do noting */
}

void FirstEntry_StayBoot_Func(void)
{
    /* ATK to PC */
    uint8 ATK_Date[8]="Staynow!";
    RS485_ComtralIO.Set_High(&RS485_ComtralIO);
    RS485_UART_Type.SendByteLen = 8;
    RS485_UART_Type.SendDateIndex = ATK_Date;
    RS485_UART_Type.Send_Date(&RS485_UART_Type);
    RS485_ComtralIO.Set_Low(&RS485_ComtralIO);
    /* Erase target flash sector */
    for (uint8_t i=0;i<128;i++)
	{
		BSP_W25Qx_Erase_Block(i*4096);/*each time erase 4096byte*/
		my_printf(">>>>>Erase SECTOR %d\r\n",i);
	}
	my_printf(">>>>>Erasing SPI Flash Done\r\n");
}

void FirstEntry_DateDeal_Func(void)
{
    /* Do noting */
}

void FirstEntry_Fault_Func(void)
{
    /* Do noting */
}

void FirstEntry_FlashDeal_Func(void)
{
    /* Do noting */
}

void FirstEntry_JumpApp_Func(void)
{
    /* Do noting */
}


void JumpToApp(void)
{


  /* 如果初始化了外设，需要反向初始化外设 */
  MCAL_USART_DeInit();
  MCAL_Timer_DeInit();
  MCAL_SPI_DeInit();
  MCAL_OutputIO_DeInit();

  /* 设置所有时钟到默认状态，使用HSI时钟 */
  HAL_RCC_DeInit();

  /* 关闭滴答定时器，复位到默认值 */
  SysTick->CTRL = 0;
  SysTick->LOAD = 0;
  SysTick->VAL = 0;

  /* 关闭全局中断 */
  DISABLE_INT();

  /* 关闭所有中断，清除所有中断挂起标志 */
  for (uint32_t i = 0; i < 8; i++)
  {
    NVIC->ICER[i]=0xFFFFFFFF;
    NVIC->ICPR[i]=0xFFFFFFFF;
  }

  /* 使能全局中断 */
  ENABLE_INT();

  /* 设置SysMemBootJump为中断服务函数入口地址，首地址是MSP，地址+4是复位中断服务程序地址 */
  SysMemBootJump = (void (*)(void)) (*((uint32_t *) (AppAddr + 4)));

  /* 设置主堆栈指针 */
  __set_MSP(*(uint32_t *)AppAddr);

  /* 在RTOS工程，这条语句很重要，设置为特权级模式，SP使用MSP指针 */
  __set_CONTROL(0);

  /* 进行跳转 也就是将SysMemBootJump 赋值给PC */
  SysMemBootJump();

}
